<template>
	<div class="json-schema-tree">
		<el-tree :data="treeData" :props="defaultProps" :expand-on-click-node="false" node-key="path"
			:default-expanded-keys="defaultExpandedKeys" @node-click="handleNodeClick" v-bind="$attrs">
			<template #default="{ node,data }">
				<span class="custom-tree-node">
					<span :class="['node-label', data.type]">
						<span class="property-name" :draggable="nodeDraggable"
							@dragstart="handleNodeDragStart($event, data)">{{ node.label }}</span>
						<span class="property-type" v-if="data.type">{{ data.type }}</span>
						<span class="property-required" v-if="data.required">*</span>
						<el-tooltip v-if="data.description" effect="dark" placement="right">
							<template #content>
								<div v-html="data.description"></div><i class="el-icon-question description-icon"></i>
							</template>
							{{data.description}}
						</el-tooltip>
					</span>
					<!--
					<span class="property-details"
						v-if="data.format || (data.enum && data.enum.length) || data.default !== undefined">
						<span v-if="data.format" class="format">format: {{ data.format }}</span>
						<span v-if="data.enum && data.enum.length" class="enum">enum:
							{{ data.enum.join(', ') }}</span>
						<span v-if="data.default !== undefined" class="default">default: {{ data.default }}</span>
					</span>
					-->
				</span>
			</template>
		</el-tree>
	</div>
</template>

<script>
	export default {
		name: 'JsonSchemaTree',
		props: {
			schema: {
				type: Object,
				required: true
			},
			expandAll: {
				type: Boolean,
				default: false
			},
			nodeDraggable: {
				type: Boolean,
				default: true
			}
		},
		data() {
			return {
				treeData: [],
				defaultProps: {
					children: 'children',
					label: 'label'
				},
				defaultExpandedKeys: []
			}
		},
		watch: {
			schema: {
				immediate: true,
				handler(schema) {
					if (schema) {
						this.processSchema(schema);
					} else {
						this.treeData = [];
					}
				}
			}
		},
		methods: {
			processSchema(schema) {
				try {
					this.treeData = this.convertSchemaToTreeData(schema);
					if (this.expandAll) {
						this.defaultExpandedKeys = this.getAllPaths(this.treeData);
					}
				} catch (error) {
					console.error('Error processing schema:', error);
					this.treeData = [{
						label: 'Error parsing schema',
						type: 'error',
						path: '/error'
					}];
				}
			},

			getAllPaths(nodes, paths = []) {
				if (!nodes) return paths;

				for (const node of nodes) {
					if (node.path) {
						paths.push(node.path);
					}
					if (node.children && node.children.length > 0) {
						this.getAllPaths(node.children, paths);
					}
				}

				return paths;
			},

			convertSchemaToTreeData(schema, parentPath = '', isRoot = true) {
				if (!schema) return [];

				// 如果是根节点，直接解析
				if (isRoot) {
					const rootData = {
						label: schema.title || 'Root Schema',
						type: schema.type || 'object', // 默认为 object 类型
						description: schema.description || '',
						path: '/',
						required: false,
						children: []
					};

					// 处理 properties
					if (schema.properties) {
						const requiredProps = Array.isArray(schema.required) ? schema.required : [];
						for (const key in schema.properties) {
							const property = schema.properties[key] || {};
							const isRequired = requiredProps.includes(key);
							const propertyPath = `/${key}`;

							try {
								const nodeData = this.createNodeData(
									key,
									property,
									propertyPath,
									isRequired
								);

								rootData.children.push(nodeData);
							} catch (error) {
								console.error(`Error processing property ${key}:`, error);
							}
						}
					}

					return [rootData];
				} else {
					// 非根节点的处理
					const nodeData = [];

					if (schema.type === 'object' && schema.properties) {
						const requiredProps = Array.isArray(schema.required) ? schema.required : [];
						for (const key in schema.properties) {
							const property = schema.properties[key] || {};
							const isRequired = requiredProps.includes(key);
							const propertyPath = parentPath ? `${parentPath}/${key}` : key;

							try {
								const propNodeData = this.createNodeData(
									key,
									property,
									propertyPath,
									isRequired
								);

								nodeData.push(propNodeData);
							} catch (error) {
								console.error(`Error processing property ${key}:`, error);
							}
						}
					} else if (schema.type === 'array' && schema.items) {
						const itemPath = `${parentPath}/items`;
						const itemLabel = 'items';

						try {
							const itemNodeData = this.createNodeData(
								itemLabel,
								schema.items,
								itemPath,
								false
							);

							nodeData.push(itemNodeData);
						} catch (error) {
							console.error('Error processing array items:', error);
						}
					}

					return nodeData;
				}
			},

			createNodeData(key, schema, path, required) {
				if (!schema) {
					schema = {};
				}

				const nodeData = {
					label: key,
					type: schema.type || 'unknown',
					description: schema.description || '',
					format: schema.format || '',
					enum: Array.isArray(schema.enum) ? schema.enum : [],
					default: schema.default,
					path: path,
					required: required,
					children: []
				};

				// 递归处理嵌套结构
				if (schema.type === 'object' && schema.properties) {
					try {
						nodeData.children = this.convertSchemaToTreeData(schema, path, false);
					} catch (error) {
						console.error(`Error processing object properties at ${path}:`, error);
					}
				} else if (schema.type === 'array' && schema.items) {
					try {
						nodeData.children = this.convertSchemaToTreeData({
								properties: {
									items: schema.items
								}
							},
							path,
							false
						);
					} catch (error) {
						console.error(`Error processing array items at ${path}:`, error);
					}
				}

				return nodeData;
			},

			handleNodeClick(data) {
				this.$emit('node-click', data);
			},

			handleNodeDragStart(event, data) {
				/*
				event.dataTransfer.setData('text/plain', variable.var);
				event.dataTransfer.effectAllowed = 'copy';
				*/
				this.$emit('node-dragstart', {
					event: event,
					data: data
				})
			}
		}
	}
</script>

<style scoped>
	.json-schema-tree {
		font-family: 'Consolas', 'Monaco', monospace;
		height: 100%;
	}

	.custom-tree-node {
		flex: 1;
		display: flex;
		align-items: flex-start;
		justify-content: space-between;
		font-size: 14px;
		padding-right: 8px;
		flex-direction: column;
	}

	.node-label {
		display: flex;
		align-items: center;
	}

	.property-name {
		font-weight: bold;
		margin-right: 6px;
	}

	.property-type {
		font-size: 12px;
		color: #67c23a;
		background-color: rgba(103, 194, 58, 0.1);
		padding: 2px 6px;
		border-radius: 3px;
		margin-right: 6px;
	}

	.node-label.string .property-type {
		color: #409EFF;
		background-color: rgba(64, 158, 255, 0.1);
	}

	.node-label.number .property-type,
	.node-label.integer .property-type {
		color: #E6A23C;
		background-color: rgba(230, 162, 60, 0.1);
	}

	.node-label.boolean .property-type {
		color: #F56C6C;
		background-color: rgba(245, 108, 108, 0.1);
	}

	.node-label.array .property-type {
		color: #9C27B0;
		background-color: rgba(156, 39, 176, 0.1);
	}

	.node-label.object .property-type {
		color: #67c23a;
		background-color: rgba(103, 194, 58, 0.1);
	}

	.node-label.unknown .property-type {
		color: #909399;
		background-color: rgba(144, 147, 153, 0.1);
	}

	.property-required {
		color: #F56C6C;
		margin-right: 6px;
	}

	.description-icon {
		color: #909399;
		font-size: 14px;
		cursor: pointer;
	}

	.property-details {
		font-size: 12px;
		color: #606266;
		margin-left: 18px;
		margin-top: 4px;
		display: flex;
		flex-wrap: wrap;
		gap: 8px;
	}

	.format,
	.enum,
	.default {
		background-color: #f5f7fa;
		padding: 2px 6px;
		border-radius: 3px;
	}
</style>
